package io.kimmking.rpcfx.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.timeout.IdleStateHandler;

import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.TimeUnit;

/**
 * Create by chenhd on 2021/10/7.
 */
public class NettyClient {

    /**
     * 客户端业务处理handler
     */
    private ClientHandler clientHandler = new ClientHandler();

    /**
     * 事件池
     */
    private EventLoopGroup group = new NioEventLoopGroup();

    /**
     * 启动器
     */
    private Bootstrap bootstrap = new Bootstrap();

    /**
     * 客户端通道
     */
    private Channel clientChannel;

    /**
     * 客户端连接
     *
     * @param url
     */
    public NettyClient(String url) throws MalformedURLException {
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.SO_REUSEADDR, true)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.AUTO_CLOSE, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel channel) throws Exception {
                        channel.pipeline().addLast("idleStateHandler", new IdleStateHandler(5, 5, 12));
                        channel.pipeline().addLast("httpRespDecoder", new HttpResponseDecoder());
                        // 避免response太大解析不了
                        channel.pipeline().addLast("httpAggregator", new HttpObjectAggregator(2097152));
                        channel.pipeline().addLast("httpReqEncoder", new HttpRequestEncoder());
//                        channel.pipeline().addLast("httpRespDecoder", new MyDecoder());
//                        channel.pipeline().addLast("httpReqEncoder", new MyEncoder());
                        channel.pipeline().addLast("clientHandler", clientHandler);
                    }
                });

        //发起同步连接操作
        URL urlObj = new URL(url);
        String host = urlObj.getHost();
        int port = urlObj.getPort();
        ChannelFuture channelFuture = bootstrap.connect(host, port);

        //注册连接事件
        channelFuture.addListener((ChannelFutureListener) future -> {
            //如果连接成功
            if (future.isSuccess()) {
                clientChannel = channelFuture.channel();
            }
            //如果连接失败，尝试重新连接
            else {
                future.channel().close();
                bootstrap.connect(host, port);
            }
        });

        //注册关闭事件
        channelFuture.channel().closeFuture().addListener(cfl -> {
            close();
        });
    }

    /**
     * 客户端关闭
     */
    private void close() {
        //关闭客户端套接字
        if (clientChannel != null) {
            clientChannel.close();
        }
        //关闭客户端线程组
        if (group != null) {
            group.shutdownGracefully();
        }
    }

    /**
     * 客户端发送消息
     *
     * @param message
     * @return
     * @throws InterruptedException
     */
    public String send(String url, Object message) throws InterruptedException, MalformedURLException, UnsupportedEncodingException {
        ChannelPromise promise = clientHandler.sendMessage(url, message);
        promise.await(3, TimeUnit.SECONDS);
        return clientHandler.getResponse();
    }
}